package br.mestrado.unb.bs.protocol;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import br.mestrado.unb.bs.model.constant.DataPackageConstant;
import br.mestrado.unb.bs.model.sensor.CommandPayload;
import br.mestrado.unb.bs.model.sensor.DataPackageWrapper;
import br.mestrado.unb.bs.model.sensor.PayloadInterface;
import br.mestrado.unb.bs.util.Log;

public class ProtocolParser extends Thread{
	
	private List<byte[]> buffers;
	private List<DataPackageWrapper> packs;
	private Object blocker;
	private Object packsBlocker;
	
	
	ProtocolParser(){
		packsBlocker = new Object();
		blocker	= new Object();
		buffers = new ArrayList<byte[]>();
		packs	= new ArrayList<DataPackageWrapper>();
		this.setName("ProtocolParser");
	}
	
	public void onDestroy() {
		this.buffers.clear();
		this.packs.clear();		
	}

	public void parseWrapPackage(int i, int j, byte[] buffer){
		synchronized (buffers) {
			this.buffers.add(Arrays.copyOfRange(buffer, i, (j + 1)));
		}
		synchronized (this.blocker) {
			this.blocker.notify();		
		}
	}
	
	
	@Override
	public void run() {
		while(true){
			if(buffers.isEmpty()){
				synchronized (this.blocker) {
					try {
						blocker.wait();
					} catch (InterruptedException e) {
						System.out.println("Thread interrompida: "+getName());
						break;
					}
				}
			}
			parse();
		}
	}

	public List<DataPackageWrapper> getDataPackageWrappers(){
		if(packs==null || packs.isEmpty()){
			synchronized (packsBlocker) {
				try {
					packsBlocker.wait();
				} catch (InterruptedException e) {
					Log.w(getName(),"Theard "+ getName() +" interrompida.");
				}
			}
		}
		synchronized (packs) {
			List<DataPackageWrapper> copy = new ArrayList<DataPackageWrapper>(this.packs);
			this.packs.clear();
			return copy;
		}
	}
	
	private void parse() {
		int size  = buffers.size();
		for (int i = 0; i < size; i++) {
			PayloadInterface payload = doPayloadParser(buffers.get(i));  
			DataPackageWrapper data = new DataPackageWrapper(payload);
			synchronized (packs) {
				packs.add(data);
			}
		}
		synchronized (packsBlocker) {
			packsBlocker.notifyAll();
		}
		synchronized (buffers) {
			buffers.clear();
		}
	}

	private PayloadInterface doPayloadParser(byte[] bs) {
		byte category 	= bs[DataPackageConstant.i_payload_category];
		byte battery	= bs[DataPackageConstant.i_battery];
		switch (category) {
			case DataPackageConstant.command_category:
				byte commandValue	= bs[DataPackageConstant.i_init_payload + DataPackageConstant.i_command_value];
				byte sensorCategory	= bs[DataPackageConstant.i_init_payload + DataPackageConstant.i_command_sensor_category];
				byte sensorId		= bs[DataPackageConstant.i_init_payload + DataPackageConstant.i_command_sensor_id];
				byte newValue		= bs[DataPackageConstant.i_init_payload + DataPackageConstant.i_command_new_value];
				CommandPayload comm	= new CommandPayload(commandValue,sensorCategory,sensorId,newValue);
				comm.setBattery(battery);
				comm.setCategory(category);
				return comm;
			default:
				break;
		}
		return null;
	}

}